package ch.fusun.baron.basic.turntask;

import java.util.Collection;
import java.util.LinkedList;
import java.util.List;

import ch.fusun.baron.city.City;
import ch.fusun.baron.city.api.CityService;
import ch.fusun.baron.core.injection.Inject;
import ch.fusun.baron.farm.Farm;
import ch.fusun.baron.farm.FarmService;
import ch.fusun.baron.map.Tile;
import ch.fusun.baron.map.api.GameMapService;
import ch.fusun.baron.player.api.Country;
import ch.fusun.baron.player.api.CountryService;
import ch.fusun.baron.property.api.PropertyService;
import ch.fusun.baron.turn.TurnTask;

/**
 * Checks if there is enough food for all citizens and kills surplus
 */
public class CitySurvivalTurnTask implements TurnTask {

	@Inject
	private FarmService farmService;
	@Inject
	private GameMapService mapService;
	@Inject
	private PropertyService propertyService;
	@Inject
	private CityService cityService;
	@Inject
	private CountryService countryService;

	/**
	 * Constructor
	 */
	public CitySurvivalTurnTask() {
	}

	@Override
	public void execute() {
		for (Country country : countryService.getCountries()) {
			Collection<Farm> farms = getFarmsForCountry(country);
			Collection<City> cities = getCitiesForCountry(country);
			for (City city : cities) {
				Tile location = cityService.getLocation(city);
				int food = getNumberOfFarmsNearestTo(location, cities, farms);
				city.setPopulation(Math.min(city.getPopulation(), food));
				if (city.isDead()) {
					cityService.removeCity(city);
				}
			}
		}
	}

	private Collection<City> getCitiesForCountry(Country country) {
		List<City> cities = new LinkedList<City>();
		for (Tile tile : mapService.getTiles()) {
			City city = cityService.getCity(tile);
			if (city != null) {
				if (country.equals(propertyService.getOwnership(tile))) {
					cities.add(city);
				}
			}
		}
		return cities;
	}

	private Collection<Farm> getFarmsForCountry(Country country) {
		List<Farm> farms = new LinkedList<Farm>();
		for (Tile tile : mapService.getTiles()) {
			Farm farm = farmService.getFarm(tile);
			if (farm != null) {
				if (country.equals(propertyService.getOwnership(tile))) {
					farms.add(farm);
				}
			}
		}
		return farms;
	}

	private int getNumberOfFarmsNearestTo(Tile location,
			Collection<City> cities, Collection<Farm> farms) {
		int food = 0;
		for (Farm farm : farms) {
			Tile farmLocation = farmService.getLocation(farm);
			double shortestDistance = Double.MAX_VALUE;
			Tile nearestLocation = new Tile(Integer.MAX_VALUE,
					Integer.MAX_VALUE);
			for (City city : cities) {
				Tile cityLocation = cityService.getLocation(city);
				if (farmLocation.absoluteDistanceTo(cityLocation) <= shortestDistance) {
					nearestLocation = cityLocation;
					shortestDistance = farmLocation
							.absoluteDistanceTo(cityLocation);
				}
			}
			if (nearestLocation.equals(location)) {
				food++;
			}
		}
		return food;
	}

}
